#include<iostream>
#include<ctype.h>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<unordered_map>
#include<sys/stat.h>
#include<fcntl.h>

#define COMMAND_SIZE 1024
#define FORMAT "[%s@%s %s]# "
//下面是shell定义的全局数据
#define MAXARGC 128
char *g_argv[MAXARGC];
int g_argc=0;
//2环境变量表
#define MAX_ENVS 100
char *g_env[MAX_ENVS];
int g_envs=0;

//3别名映射表

std::unordered_map<std::string ,std::string> alias_list;
//4关于重定向
#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3

int redir=NONE_REDIR;
std::string filename;

char cwd[1024];
char cwdenv[1024];
const char *GetUserName(){
  const char *name=getenv("USER");
  return name==NULL?"None":name;

}
const char *GetHostName(){
  const char *hostname=getenv("HOSTNAME");
  return hostname==NULL?"None":hostname;

}

const char *GetPwd(){
  //const char *pwd=getenv("PWD");
  const char* pwd=getcwd(cwd,sizeof(cwd));
  if(pwd!=NULL){
    snprintf(cwdenv,sizeof(cwdenv),"PWD=%s",cwd);
    putenv(cwdenv);
  }
  return pwd==NULL?"None":pwd;
}

const char* GetHome(){
  const char *home=getenv("HOME");
  return home==NULL?" ":home;
}

// / a/b/c
const char *DirName(const char *pwd)
{
#define SLASH "/"
  std::string dir=pwd;
  if(dir==SLASH)return SLASH;
  auto pos=dir.rfind(SLASH);
  if(pos==std::string::npos)return "BUG";
  return dir.substr(pos+1).c_str();
  
}

void MakeCommandLine(char cmd_prompt[],int size)
{
  snprintf(cmd_prompt,size,FORMAT,GetUserName(),GetHostName(),DirName(GetPwd()));
}
void PrintCommandPrompt(){
  char prompt[COMMAND_SIZE];
  MakeCommandLine(prompt,sizeof(prompt));
  printf("%s",prompt);
  fflush(stdout);
}

bool GetCommandLine(char* out,int size){
    char *c=fgets(out,size,stdin);
    if(c==NULL) return false;
    out[strlen(out)-1]=0;
    if(strlen(out)==0) return false;
    return true;
}
//命令行分析
bool GetCommandParse(char *commandline){
#define SEP " "
    g_argc=0;
    g_argv[g_argc++]=strtok(commandline,SEP);
    while((g_argv[g_argc] = strtok(g_argc==0?commandline:nullptr,SEP))&&g_argc<MAXARGC-1){
      g_argc++;
    }
    return true;
}

void PrintArgv(){
  for(int i=0;g_argv[i];i++){
    printf("argv[%d]->%s\n",i,g_argv[i]);
  }
  printf("argc: %d\n",g_argc);

}


bool CheckAndExecBuiltin(){
  std::string cmd=g_argv[0];
  if(cmd=="cd"){
    if(g_argc==0){
      std::string home =GetHome();
      if(home.empty()) return true;
      chdir(home.c_str());

    }
    else {
      std::string where=g_argv[1];

      if(where=="-"){

      }
      else if(where=="~"){

      }
      else{
        chdir(where.c_str());
      }
    }
    return true;

  }
  return false;
}

int Execute(){
    pid_t id=fork();
    if(id==0)
    {
      int fd=-1;
      //子进程检测重定向情况
      if(redir==INPUT_REDIR){
        fd=open(filename.c_str(),O_RDONLY,0666);
        if(fd<0) exit(1);
        dup2(fd,0);
        close(fd);
      }
      else if(redir==OUTPUT_REDIR){
        
        fd=open(filename.c_str(),O_CREAT | O_WRONLY | O_TRUNC,0666);
        if(fd<0) exit(2);
        dup2(fd,1);
        close(fd);
      }
      else if(redir==APPEND_REDIR){
        fd=open(filename.c_str(),O_CREAT | O_WRONLY | O_APPEND,0666);
        
        if(fd<0) exit(3);
        dup2(fd,1);

        close(fd);
      }
      else{
        
      }
      //child
      execvp(g_argv[0],g_argv);
      exit(1);
    }
    pid_t rid=waitpid(id,nullptr,0);
    (void)rid;
    return 0;

}
void TrimSpace(char cmd[],int &end){
  while(isspace(cmd[end])){
    end++;
  }  
}

void RedirCheck(char cmd[]){
  redir=NONE_REDIR;
  filename.clear();
  int start=0;
  int end=strlen(cmd)-1;
  while(end>start){
    if(cmd[end]=='<'){
      cmd[end++]=0;
      TrimSpace(cmd,end);
      redir =INPUT_REDIR;
      filename=cmd+end;
      break;
    }
    else if(cmd[end]=='>'){
      if(cmd[end-1]=='>'){
        //>>
        cmd[end-1]=0;
        redir =APPEND_REDIR;
      }
      else{
        //>
        redir =OUTPUT_REDIR;
      }
        cmd[end++]=0;
        TrimSpace(cmd,end);
        filename=cmd+end;
        break;
    }
    else{
      end--;
    }
  }
}

int main()
{
  while(true){
    redir=NONE_REDIR;
    filename.clear();
    //1输出命令提示符
    PrintCommandPrompt();
    //2获取用户输入的命令
    char commandline[COMMAND_SIZE];
    if(!GetCommandLine(commandline,sizeof(commandline)))
      continue;
    //3重定向分析
    RedirCheck(commandline);
    //printf("redir: %d,filename: %s\n",redir,filename.c_str());
    //4命令行分析 ”ls -a -l“
    GetCommandParse(commandline);
    //PrintArgv();
    //5检测并处理内键命令
    if( CheckAndExecBuiltin()){
      continue;
    }
    //执行命令
    Execute();
  }
  return 0;
}




